<template>
	<view class="content">
		<!-- 单词+图片 -->
		<view class="word_text_img">
			<!-- <image class="logo" src="/static/banana.jpeg"></image> -->
			<view class="logo"><text class="title">问：你要去哪儿呢？</text></view>
			<view class="word-area">
				<text class="title">{{ sayData }}</text>
			</view>
		</view>

		<!-- 按钮组 -->
		<view class="but-area">
			<!-- 原声 -->
			<view class="but"></view>
			<!-- 朗读 -->
			<view class="but_garden" @touchstart.stop="startRecord" @touchend.stop="endRecord">录音</view>
			<!-- 下一个 -->
			<view class="but"></view>
		</view>
	</view>
</template>

<script>
// 1. websocket连接：判断浏览器是否兼容，获取websocket url并连接，这里为了方便本地生成websocket url
// 2. 获取小程序录音权限，
// 3. 小程序获取录音数据
// 4. 将录音数据处理为文档要求的数据格式：采样率16k或8K、位长16bit、单声道；该操作属于纯数据处理，使用webWork处理
// 5. 根据要求（采用base64编码，每次发送音频间隔40ms，每次发送音频字节数1280B）将处理后的数据通过websocket传给服务器，
// 6. 实时接收websocket返回的数据并进行处理

import { Base64 } from '../../js/base64js.js';
import '../../js/enc-base64-min';
import CryptoJS from '../../js/hmac-sha256.js';

// 鉴权码：从讯飞开放平台申请appid，并添加（流式接口）获取接口密钥APIKey 和 APISecret
// const APPID = '08c1a943';
// const API_SECRET = 'NmQ5YmY0Nzg4MmU0YTQzNGU0NmM5OWMy';
// const API_KEY = '5cbaed332e3e5b1dbbb8959e4d59b879';
const APPID = '5ea56f0b';
const API_SECRET = '9ebe4396db7dbe3c103bb9503aca59cf';
const API_KEY = '2243790bcd6f0d8cd062806d2e98ff7c';

// 获取录音
const recorderManager = uni.getRecorderManager();
const innerAudioContext = uni.createInnerAudioContext();

innerAudioContext.autoplay = true;
export default {
	data() {
		return {
			webSocket: '',
			// 打开设置 授权录音功能
			recordShow: false,
			voicePath: '',
			audioData: [],
			sayData: '*这儿显示您说的话*'
		};
	},
	onLoad() {
		let self = this;
		recorderManager.onStop(function(res) {
			self.voicePath = res.tempFilePath;
			var tempFilePath = res.tempFilePath; //音频文件地址
			// #ifdef APP-PLUS
			plus.io.resolveLocalFileSystemURL(tempFilePath,function(entry){
				entry.file(function(file) {
					let fileReader = new plus.io.FileReader();
					fileReader.readAsDataURL(file);
					fileReader.onloadend = function (res) {
						console.log('读取文件:'+ res.target.result);
						self.audioData = Array.from(new Uint8Array(res.target.result));//self.transcode(res);		//Array.from(new Uint8Array())

						self.webSocketSend();
					}
				})
			})
			// #endif
			// #ifdef MP-WEIXIN
			const fs = uni.getFileSystemManager();
			fs.readFile({
				//读取文件并转为ArrayBuffer
				filePath: tempFilePath,
				success(res) {
					console.log('读取文件:' + res.data);
					self.audioData = Array.from(new Uint8Array(res.data));
					self.webSocketSend();
				}
			});
			// #endif
		});
		recorderManager.onFrameRecorded(function(res) {
			console.log('recorder onFrameRecorded', res);
		});
		// 链接 WebSocket
		// this.connectWebSocket();
		//自动播放语音
		// this.playVoice();
	},
	onShow() {
		// 判断用户是否有授权注册
		// 可以通过 uni.getSetting 先查询一下用户是否授权了录音功能
		// #ifdef MP-WEIXIN
		uni.getSetting({
			success: res => {
				if (res.authSetting['scope.record'] === undefined) {
					// 授权录音
					uni.authorize({
						scope: 'scope.record',
						success: els => {
							// console.log('成功', els)
							this.recordShow = true;
						},
						fail: els => {
							// console.log('失败', els)
							this.recordShow = false;
						}
					});
				} else {
					this.recordShow = res.authSetting['scope.record'];
				}
			}
		});
		// #endif
	},
	methods: {
		// 长按录制
		startRecord() {
			this.connectWebSocket();
			console.log('开始录音');
			// 显示 loading 提示框
			uni.showLoading({
				title: '录制中'
			});
			/*
			开发语言	任意，只要可以向讯飞云服务发起Websocket请求的均可
			音频属性	采样率16k、位长16bit、单声道
			音频格式	pcm、wav、mp3（需更改aue的值为lame）、speex-wb;7
			音频大小	音频数据发送会话时长不能超过5分钟
			语言种类	中文、英文
			#
			*/
			// recorderManager.start();
			recorderManager.start({
				duration: 30000, // 600000（10 分钟）,默认值 60000（1 分钟）
				numberOfChannels: 1, // 录音通道数，有效值 1/2
				format: 'pcm', // 音频格式
				sampleRate: 16000 // 采样率
			});
		},
		// 松开停止
		endRecord() {
			console.log('录音结束');
			// 隐藏 loading 提示框
			uni.hideLoading();
			recorderManager.stop();
		},
		// 播放
		playVoice() {
			console.log('连续播放音频');
			innerAudioContext.src = '/static/ad2.m4a';
			innerAudioContext.onPlay(() => {
				console.log('开始播放');
			});
			innerAudioContext.onEnded(() => {
				// console.log('上一个播放完了')
				// innerAudioContext.src = "/static/ad2.m4a";
				// innerAudioContext.play();
				// innerAudioContext.offEnded()//取消播放
			});
		},
		// 生成握手参数
		getWebSocketUrl() {
			return new Promise((resolve, reject) => {
				// 请求地址根据语种不同变化
				var url = 'wss://iat-api.xfyun.cn/v2/iat';
				var host = 'iat-api.xfyun.cn';
				var apiKey = API_KEY;
				var apiSecret = API_SECRET;
				var date = new Date().toGMTString();
				var algorithm = 'hmac-sha256';
				var headers = 'host date request-line';
				var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/iat HTTP/1.1`;
				var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
				var signature = CryptoJS.enc.Base64.stringify(signatureSha);
				var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
				var authorization = Base64.btoa(authorizationOrigin);
				url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
				resolve(url);
			});
		},
		// 连接websocket
		connectWebSocket() {
			let that = this;
			return this.getWebSocketUrl().then(url => {
				console.log(url);
				uni.connectSocket({
					url: encodeURI(url)
				});
				uni.onSocketOpen(function(res) {
					console.log('WebSocket连接已打开！');
				});
				uni.onSocketError(function(res) {
					console.log('WebSocket连接打开失败，请检查！');
				});
				uni.onSocketMessage(function(res) {
					console.log('收到服务器内容：' + res.data);
					that.result(res.data);
				});
			});
		},
		// 对处理后的音频数据进行base64编码
		toBase64(buffer) {
			var binary = ''
			var bytes = new Uint8Array(buffer)
			var len = bytes.byteLength
			for (var i = 0; i < len; i++) {
			  binary += String.fromCharCode(bytes[i])
			}
			return Base64.btoa(binary);
		},
		// 向webSocket发送数据
		webSocketSend() {
			console.log('=====webSocketSend=====');
			// if (this.webSocket.readyState !== 1) {
			// 	return;
			// }
			let audioData = this.audioData.splice(0, 1280);
			var params = {
				common: {
					app_id: APPID
				},
				business: {
					language: 'zh_cn', //小语种可在控制台--语音听写（流式）--方言/语种处添加试用
					domain: 'iat',
					accent: 'mandarin', //中文方言可在控制台--语音听写（流式）--方言/语种处添加试用
					vad_eos: 3000,
					dwa: 'wpgs' //为使该功能生效，需到控制台开通动态修正功能（该功能免费）
				},
				data: {
					status: 0,
					format: 'audio/L16;rate=16000',
					encoding: 'raw',
					audio: this.toBase64(audioData)
				}
			};
			console.log('------初始化头部数据--流式分片发送数据到讯飞平台------');
			uni.sendSocketMessage({
				data: JSON.stringify(params)
			});
			// this.webSocket.send(JSON.stringify(params))
			this.handlerInterval = setInterval(() => {
				console.log('------具体内容数据--流式分片发送数据到讯飞平台------');
				// 最后一帧
				if (this.audioData.length === 0) {
					// if (this.status === 'end') {
					uni.sendSocketMessage({
						data: JSON.stringify({
							data: {
								status: 2,
								format: 'audio/L16;rate=16000',
								encoding: 'raw',
								audio: ''
							}
						})
					});
					this.audioData = [];
					clearInterval(this.handlerInterval);
					// }
					return false;
				}
				audioData = this.audioData.splice(0, 1280);
				// 中间帧
				uni.sendSocketMessage({
					data: JSON.stringify({
						data: {
							status: 1,
							format: 'audio/L16;rate=16000',
							encoding: 'raw',
							audio: this.toBase64(audioData)
						}
					})
				});
			}, 40);
		},
		result(resultData) {
			// 识别结束
			let jsonData = JSON.parse(resultData);
			if (jsonData.data && jsonData.data.result) {
				let data = jsonData.data.result;
				let str = '';
				let resultStr = '';
				let ws = data.ws;
				for (let i = 0; i < ws.length; i++) {
					str = str + ws[i].cw[0].w;
				}
				// 开启wpgs会有此字段(前提：在控制台开通动态修正功能)
				// 取值为 "apd"时表示该片结果是追加到前面的最终结果；取值为"rpl" 时表示替换前面的部分结果，替换范围为rg字段
				if (data.pgs) {
					if (data.pgs === 'apd') {
						// 将resultTextTemp同步给resultText
						// this.setResultText({
						// 	resultText: this.resultTextTemp
						// });
						this.setResultText(this.resultTextTemp);
					}
					// 将结果存储在resultTextTemp中
					this.setResultText(str);
				} else {
					this.setResultText(str);
				}
			}
			if (jsonData.code === 0 && jsonData.data.status === 2) {
				uni.onSocketClose(function(res) {
					console.log('WebSocket 已关闭！');
				});
			}
			if (jsonData.code !== 0) {
				uni.onSocketClose(function(res) {
					console.log('WebSocket 已关闭！');
				});
				console.log(`${jsonData.code}:${jsonData.message}`);
			}
		},
		setResultText(result) {
			console.log('最终结果' + result);
			uni.showToast({
				title: '讯飞返回结果成功',
				icon: 'none'
			});
			this.sayData = result; //文本
		}
	}
};
</script>

<style>
.content {
	height: 100vh;
	background: #fafbfc;
}

.word_text_img {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	background: #ffffff;
	border-radius: 8px;
	margin: 16px;
	box-shadow: 0px 0px 15px #ebeef5;
}

.logo {
	height: 600rpx;
	width: 400rpx;
	margin-top: 100rpx;
	margin-left: auto;
	margin-right: auto;
	margin-bottom: 50rpx;
}

.word-area {
	margin-bottom: 100rpx;
	display: flex;
	justify-content: center;
}
.logo .title {
	font-size: 43rpx;
	color: #007aff;
}
.word-area .title {
	font-size: 46rpx;
	color: #ff0c1c;
}

.measurement {
	padding: 16px;
	border-radius: 8px;
	color: #909399;
	font-size: 16px;
	display: flex;
	align-items: center;
	justify-content: space-between;
}

.measurement .title {
	font-size: 32rpx;
	color: #007aff;
}

/* 按钮组 */
.but-area {
	padding: 16px;
	display: flex;
	align-items: center;
	justify-content: space-between;
}

.but-area .but {
	width: 100px;
	color: #007aff;
	line-height: 46px;
	text-align: center;
	background: #ffffff;
	border-radius: 23px;
	box-shadow: 0px 0px 8px #ebeef5;
}

.but-area .but_garden {
	width: 80px;
	line-height: 80px;
	text-align: center;
	background: #007aff;
	color: #ffffff;
	border-radius: 50%;
	box-shadow: 0px 0px 8px #ebeef5;
}
</style>
